package dm.bsi;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Field;

import org.dom4j.DocumentException;

import algo.LoadBalance;
import dm.service.DpServiceManager;
import indi.zjh.dp.db.Session;
import indi.zjh.dp.error.UnsuportedFieldException;
import indi.zjh.dp.orm.Relation;
import indi.zjh.dp.type.String256;

public class WDeployment extends Deployment {
	protected int expectedWokerCount = 0;
	
	
	/**
	 * 处理容器
	 */
	public void processContainer(Session session) throws Exception
	{
		try{
		// 获取关联的Service对象
		Service service = this.getService(session);
		// 获取Service关联的容器
		long[] containerIds = service.getContainers().getIds();
		int realContainerCount = 0;
		
		DpServiceManager manager = new DpServiceManager();
		manager.process(session, this, service);
		
		// 遍历Container, 检测状态
		for(int i = 0; i < containerIds.length; ++i)
		{
			Container container = (Container)session.getById(Container.class, containerIds[i]);
//			// 容器正常运行
//			if(container.isRunning(session))
//			{
//				++realContainerCount;
//			}
//			// 容器挂掉
//			else
//			{
//				if(container.getState() == Container.NOT_RUNNING)
//				{
//					container.destory(session, service);
//					Log.info(session, this, "删除没有运行的容器, "+container.getNode(session).getIp()+":"+container.getDockerPort());
//				}
//			}
			try
			{
				manager.ping(session, this, container);
				++realContainerCount;
			}
			catch(Exception e)
			{
				container.destory(session, service);
				Log.info(session, this, "删除没有运行的容器, "+container.getNode(session).getIp()+":"+container.getDockerPort());
			}
			
		}
		
		// 正常运行的容器小于期望值
		if(realContainerCount < this.getExpectedWokerCount())
		{
			Image image = this.getImage(session);
			Node[] nodes = Node.listReadyNodes(session);
			
			if(nodes.length > 0)
			{
				Node selectedNode = LoadBalance.getIdlestNode(nodes);
				selectedNode.downloadImage(session, image);
				Container newContainer = new Container();
				newContainer.start(session, this, selectedNode, image, false, null);
				Service.agentUpdate(session);
				Log.info(session, this, "正常运行的容器个数小于预期值, 启动新容器, "+selectedNode.getIp()+":"+newContainer.getDockerPort());
				return;
			}
		}
		// 运行容器个数超过期望值, 删除多余容器
		else if(realContainerCount > this.getExpectedWokerCount())
		{
			long[] newcontainerIds = service.getContainers().getIds();
			// 删除第一个running容器
			for(int i = 0; i < newcontainerIds.length; ++i)
			{
				Container deletingContainer = (Container)session.getById(Container.class, newcontainerIds[0]);
				Node relNode = deletingContainer.getNode(session);
				if(deletingContainer.isRunning(session) && relNode.isReady())
				{
					deletingContainer.destory(session, service);
					Log.info(session, this, "运行的容器大于预期值, 删除容器, "+relNode.getIp()+":"+deletingContainer.getDockerPort());
					return;
				}
			}	
			Service.agentUpdate(session);
		}
		
		// 删除旧版本的容器
		{
			Image deployImage = this.getImage(session);
			boolean isUpdate = false;
			containerIds = service.getContainers().getIds();
			
			// 遍历Container, 检测状态
			for(int i = 0; i < containerIds.length; ++i)
			{
				Container container = (Container)session.getById(Container.class, containerIds[i]);
				// 容器正常运行
				if(container.isRunning(session))
				{
					Image containerImage = container.getImage(session);
					// 容器镜像与部署镜像期望不一致, 删除容器
					if(containerImage != null && !containerImage.getName().equals(deployImage.getName()))
					{
						container.destory(session, service);
						isUpdate = true;
						Log.info(session, this, "容器版本升级, "+container.getNode(session).getIp()+":"+container.getDockerPort());
						break;
					}
				}		
			}
			// 更新nginx代理
			if(isUpdate)
			{
				Service.agentUpdate(session);
			}
		}
		
		}catch(Exception e)
		{
			StringWriter sw = new StringWriter();
			e.printStackTrace(new PrintWriter(sw));
			Log.failure(session, this, sw.toString());
		}
	}
	
	public static String toDictString(Field f)
	{
		if(f.getName().equals("expectedWokerCount"))
		{
			return "期待的工作节点的个数";
		}
		return Deployment.toDictString(f);
	}

	public int getExpectedWokerCount() {
		return expectedWokerCount;
	}

	public void setExpectedWokerCount(int expectedWokerCount) {
		this.expectedWokerCount = expectedWokerCount;
	}



	@Override
	public String toString() {
		return "WDeployment [expectedWokerCount=" + expectedWokerCount + ", name=" + name + ", description="
				+ description + ", hostPort=" + hostPort + ", secondHostPort=" + secondHostPort + ", containerPort="
				+ containerPort + ", curContainerPort=" + curContainerPort + ", curId=" + curId + ", mode=" + mode
				+ ", tryCount=" + tryCount + ", service=" + service + ", image=" + image + ", _id=" + _id + ", _v=" + _v
				+ "]";
	}
	
	
}
